import json
import time
import traceback
from copy import deepcopy
from datetime import datetime
from functools import partial, wraps
from typing import Dict

from mg_app_framework import (HttpBasicHandler, MesCode, TaskKey, get_handler, get_logger,
                              get_organization)


def _set_response_data(self, result):
    _response = {}
    try:
        self.mes_response_data = result
        _response = json.dumps(self.mes_response_data, ensure_ascii=False)
    except Exception as e:
        self.mes_response_data = {"code": MesCode.fail, "data": {}, "info": str(e)}
        _response = json.dumps(self.mes_response_data)
    finally:
        self.finish(_response)


def log_decorator(set_log_to_db: bool = True, log_exception: bool = True):
    """

    :param set_log_to_db: 是否将访问日志保存到数据库中，默认存储
    :param log_exception: 是否捕获异常，默认不捕获
    :return:
    """

    def wrapper(method):
        @wraps(method)
        async def func(self: HttpBasicHandler, *args, **kwargs):
            if not hasattr(self, "__set_change_response_func_flag"):
                self.mes_response_data = {}
                self.__set_change_response_func_flag = True
                self._set_response_data = partial(_set_response_data, self)
            st_time = time.time()
            request_data: Dict = deepcopy(self.data)
            call_id = request_data.get("call_id", None)
            trace_id = request_data.get("trace_id", None)
            upperpc_code = request_data.get("upperpc_code", None)
            equip_code = request_data.get("equip_code", None)
            process_code = request_data.get("process_code", None)
            user_code = request_data.get("user_code", None)
            log_items = {
                "call_id": call_id,
                "trace_id": trace_id,
                "upperpc_code": upperpc_code,
                "equip_code": equip_code,
                "process_code": process_code,
                "user_code": user_code,
                "url": self.request.uri,
                "params": request_data,
                "response": None,
                "code": None,
                "error": None,
                "time": datetime.now()
            }
            try:
                res = await method(self, *args, **kwargs)
                log_items["response"] = self.mes_response_data.get("data")
                log_items["code"] = self.mes_response_data.get("code")
                log_items["info"] = self.mes_response_data.get("info")
                return res
            except Exception as e:
                log_items["error"] = str(e)
                log_items["code"] = MesCode.fail
                if log_exception:
                    traceback.format_exc()
                raise e
            finally:
                if not set_log_to_db:
                    return
                log_items["cost_time"] = int(round(time.time() - st_time, 3) * 1000)
                try:
                    log_db = f"idi_{get_organization()}_upper_pc"
                    log_collection = "access_log"  # 访问日志
                    mongo_handler = (
                        get_handler(TaskKey.idi_server)
                        .get_database(log_db)
                        .get_collection(log_collection)
                    )
                    await mongo_handler.insert_one(log_items)
                except Exception as e:
                    get_logger().error(f"MES日志记录异常, 需要记录日志:{log_items}, 异常信息:{str(e)}")

        return func

    return wrapper
